//
//  CollectionVM.swift
//  CooperSwift_Example
//
//  Created by 计海峰 on 2021/5/24.
//  Copyright © 2021 CocoaPods. All rights reserved.
//

import Foundation
import RxDataSources
import RxSwift

private struct AssociateKeys {
    static var sectionKey: Void?
    static var sectionSubjectKey: Void?
    static var serviceSubjectKey: Void?
    static var targetBlockKey: Void?
    static var serviceBlockKey: Void?
    static var dataSourceKey: Void?
}

// MARK: - data enable
public protocol CollectionViewModelProtocol: ViewModelProtocol {
    
    // 配置 datasource
    @discardableResult
    func configDataSource() -> RxCollectionViewSectionedReloadDataSource<SectionM>
    
}

public extension CollectionViewModelProtocol {
    
    /// 配置结束 开始方法
    func initDown() {
        print("table initDown")
    }
    
    /// 配置完成
    func configDown() {
        print("collection configDown")
    }
    
    /// 下拉刷新
    func refresh() {
        print("collection refresh")
    }
    
    /// 上拉加载更多
    func pullUp()  {
        print("collection pullUp")
    }
    
    /// 返回indexpath 对应的 item
    func item(indexPath: IndexPath) -> CollectionCellConfigProtocol? {
        return self.sections[safe: indexPath.section]?.items[safe: indexPath.row]
    }
    
}


public extension CollectionViewModelProtocol where Self: UICollectionViewDelegateFlowLayout {
    func vm_collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        guard let item = item(indexPath: indexPath) else { return CGSize.zero }
        let size = item.cellSize
        if size.width > 0 && size.height > 0 {
            return size
        }
        return CGSize.zero
    }
}


// MARK: - sections
public extension CollectionViewModelProtocol {
    
    typealias SectionM = SectionModel<Any, CollectionCellConfigProtocol>
  
    // MARK: -  collection 对应 sections BehaviorSubject
    var sectionsSubject: BehaviorSubject<[SectionM]> {
        get {
            return associatedObject(forKey: &AssociateKeys.sectionSubjectKey, default: BehaviorSubject<[SectionM]>(value: self.sections), ploicy: .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        set {
            setAssociatedObject(newValue, forKey: &AssociateKeys.sectionSubjectKey, ploicy: .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
  
    // MARK: -  collection 对应 sections
    var sections: [SectionM]
    {
        get {
            return associatedObject(forKey: &AssociateKeys.sectionKey, default: [SectionM](), ploicy: .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        set {
            setAssociatedObject(newValue, forKey: &AssociateKeys.sectionKey, ploicy: .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
            self.sectionsSubject.onNext(newValue)
        }
    }

   // MARK: -  第一个section 没有的话 默认创建
   @discardableResult
   func firstSection() -> SectionM {
    if let section = self.sections.first {
           return section
       }
    self.sections += [SectionModel<Any, CollectionCellConfigProtocol>(model: "Section0", items: [])]
    return self.sections.first!
   }
    
    /// 更新cell到第一个section 会删除之前的
    /// - Parameter items: cell 对应的 数据配置 数组
    func updateFirstSectionItems(_ items: [CollectionCellConfigProtocol]) {
        var sectionOne = firstSection()
        sectionOne.items = items
        self.sections[0] = sectionOne
    }
    
    /// 添加cell 到相第一个 section
    /// - Parameter items: cell 对应的 数据配置 数组
    func addFirstSectionItems(_ items: [CollectionCellConfigProtocol]) {
        var sectionOne = firstSection()
        sectionOne.items += items
        self.sections[0] = sectionOne
    }
    
}


// MARK: - rx data source
public extension CollectionViewModelProtocol {
    
    // MARK: - dataSource 初始化
    var dataSource : RxCollectionViewSectionedReloadDataSource<SectionM>? {
        get {
            return objc_getAssociatedObject(self, &AssociateKeys.dataSourceKey) as? RxCollectionViewSectionedReloadDataSource<SectionM>
        }
        set {
            objc_setAssociatedObject(self, &AssociateKeys.dataSourceKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
    @discardableResult
    func configDataSource() -> RxCollectionViewSectionedReloadDataSource<SectionM> {
        if let ds = dataSource {
            return ds
        }
        
        dataSource = RxCollectionViewSectionedReloadDataSource<SectionM>(configureCell: { dataSource, cv, indexPath, item in
            
            let cell = cv.dequeueReusableCell(indexPath: indexPath, cls: item.cellCls())

            // 绑定数据
            cell.bindTo(item)

            // 背景色
            if let bgColor = item.bgColor {
                cell.backgroundColor = bgColor
            }

            return cell
        })

        return dataSource!
    }
    
}


// MARK: - service
public extension CollectionViewModelProtocol {
    
    typealias TargetBlock = (_ service: CollectionViewModelFromTargetServiceEnum) -> Any?
    
    // MARK: -  collection 对应 sections BehaviorSubject
    var serviceSubject: BehaviorSubject<Any> {
        get {
            return associatedObject(forKey: &AssociateKeys.serviceSubjectKey, default: BehaviorSubject(value: ""), ploicy: .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        set {
            setAssociatedObject(newValue, forKey: &AssociateKeys.serviceSubjectKey, ploicy: .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
    var serviceBlock: TargetBlock? {
        get {
            return (objc_getAssociatedObject(self, &AssociateKeys.serviceBlockKey) as? Self.TargetBlock)
        }
        set {
            objc_setAssociatedObject(self, &AssociateKeys.serviceBlockKey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC)
        }
    }
      
    
    // MARK: - 配置服务
    func configServicBlock(block: @escaping TargetBlock) -> Void {
        serviceBlock = block
    }
    
    // MARK: - 发出服务
    /// 获取当前table
    func currentCV() -> UICollectionView? {
        guard let block = serviceBlock else { return nil }
        return block(.collection) as? UICollectionView
    }
    
    /// 获取当前vc
    func currentVC() -> UIViewController? {
        guard let block = serviceBlock else { return nil }
        return block(.controller) as? UIViewController
    }
    
    /// 获取当前view
    func currentV() -> UIView? {
        guard let block = serviceBlock else { return nil }
        return block(.view) as? UIView
    }
    
    /// 获取当前vc view table
    func currentAll() -> (UIViewController, UIView, UICollectionView)? {
        guard let block = serviceBlock else { return nil }
        return (block(.all) as? (UIViewController, UIView, UICollectionView))
    }
    
    /// 刷新table
    func reloadCollection() {
        guard let block = serviceBlock else { return }
        let _ = block(.reloadCollection)
    }
    
    /// 结束编辑
    func endEdit() {
        guard let block = serviceBlock else { return }
        let _ = block(.endEdit)
    }
    
}


public extension CollectionViewModelProtocol {
    
    /// 是否完全可提交
    @discardableResult
    func checkSumbit(_ errorInfoBlock: ((_ msg: String) -> Void)? = nil) -> Dictionary<String, Any>? {
        var submitData: Dictionary<String, Any> = [:]
        var isBreak = false
        self.sections.forEach { section in
            if isBreak { return }
            section.items.forEach { row in
                if isBreak { return }
                guard let item = row as? FormModelProtocol else {
                    return
                }
                if item.isReady() {
                    submitData = submitData.add(item.sumbitData()!)
                }else {
                    if errorInfoBlock != nil {
                        errorInfoBlock!(item.errorInfo())
                    }
                    isBreak = true
                }
            }
        }
        if isBreak {
            return nil
        }
        return submitData
    }
    
    /// 当前可提交的参数
    func currentParams() -> Dictionary<String, Any> {
        var submitData: Dictionary<String, Any> = [:]
        self.sections.forEach { section in
            section.items.forEach { row in
                guard let item = row as? FormModelProtocol else {
                    return
                }
                if item.isReady() {
                    submitData = submitData.add(item.sumbitData()!)
                }
            }
        }
        return submitData
    }
    
}

public extension CollectionViewModelProtocol where Self: RefreshControllable  {
    func toState(_ state: PageLoadingState) -> Void {
        if self.serviceBlock != nil {
            guard let tv = self.serviceBlock!(.collection) as? UICollectionView else {
                return
            }
            self.rx.updateEmptyDataSet(tv, config: state.config())
        }
    }
}
